﻿//--------------------------------------------------
// TXna Game Engine
// This file belongs to the TXnaGE
// https://sourceforge.net/projects/txnagameengine/
//--------------------------------------------------


using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace sqengine.PhysicObjects
{
    /// <summary>
    /// Basic TXna Light. A light has a color, LightType, and optional direction, range and position.
    /// </summary>
    public class Light
    {
        /// <summary>
        /// Allocates a new directional light structure.
        /// </summary>
        /// <param name="lightType"></param>
        /// <param name="color"></param>
        /// <param name="position"></param>
        /// <param name="direction"></param>
        public Light(Vector3 color, Vector3 direction)
            : this(LightType.Directional, color, direction, direction, 0, 0, 0, 0)
        {
            if (direction == Vector3.Zero)
                throw new System.ArgumentException("Directional light must have a non zero direction vector.");
        }

        /// <summary>
        /// Allocates a new Spot light structure.
        /// </summary>
        /// <param name="lightType"></param>
        /// <param name="color"></param>
        /// <param name="position"></param>
        /// <param name="direction"></param>
        /// <param name="range"></param>
        /// <param name="falloff">light attenuation between the inner cone and outer parts of the spot light cone. This is a value between 1.0 and 0.0, set to 1.0 ti have same color for the inner and outer cone.</param>
        /// <param name="theta">inner cone of the spot light</param>
        /// <param name="phi">outer cone of the spot light</param>
        public Light(Vector3 color, Vector3 position, Vector3 direction, float range, float falloff, float theta, float phi) : this(LightType.Spot, color, position, direction, range, falloff, theta, phi) { }

        /// <summary>
        /// Allocates a new Point light structure.
        /// </summary>
        /// <param name="lightType"></param>
        /// <param name="color"></param>
        /// <param name="position"></param>
        /// <param name="direction"></param>
        /// <param name="range"></param>
        public Light(Vector3 color, Vector3 position, float range, float fallof) : this(LightType.Point, color, position, Vector3.Zero, range, fallof, 0, 0) { }


        /// <summary>
        /// Allocates a new light structure.
        /// </summary>
        /// <param name="lightType"></param>
        /// <param name="color"></param>
        /// <param name="position"></param>
        /// <param name="direction"></param>
        /// <param name="range"></param>
        /// /// <param name="falloff">light attenuation between the inner cone and outer parts of the spot light cone. This is a value between 1.0 and 0.0, set to 1.0 ti have same color for the inner and outer cone.</param>
        /// <param name="theta">inner cone of the spot light</param>
        /// <param name="phi">outer cone of the spot light</param>
        public Light(LightType lightType, Vector3 color, Vector3 position, Vector3 direction, float range, float fallof, float theta, float phi)
        {
            this.LightType = lightType;
            this.Color = color;
            this.position = position;
            this.Direction = direction;
            this.Range = range;
            this.Enabled = true;
            this.SpotData.Y = fallof;
            this.SpotData.Z = theta;
            this.SpotData.W = phi;
        }


        /// <summary>
        /// The type of the Light.
        /// </summary>
        public LightType LightType;


        /// <summary>
        /// Gets the lights position. Note that the w vector component holds the light type information.
        /// </summary>
        public Vector3 Position { get { return position; } }
        private Vector3 position;

        /// <summary>
        /// Sets the given position vector to the lights position (lights w component is ignored).
        /// </summary>
        /// <param name="position"></param>
        public void GetPosition(ref Vector3 position)
        {
            position.X = this.Position.X;
            position.Y = this.Position.Y;
            position.Z = this.Position.Z;
        }

        /// <summary>
        /// Sets the lights  position to the given vector.
        /// </summary>
        /// <param name="position"></param>
        public void SetPosition(ref Vector3 position)
        {
            this.position.X = position.X;
            this.position.Y = position.Y;
            this.position.Z = position.Z;
        }

        /// <summary>
        /// The diffuse color of this light.
        /// </summary>
        public Vector3 Color;

        /// <summary>
        /// Gets or sets the light direction. 
        /// </summary>
        public Vector3 Direction;

        /// <summary>
        /// Gets, sets the lights radius or effective distance. This parameter has no impact on directional lights.
        /// </summary>
        public float Range
        {
            get { return SpotData.X; }
            set { SpotData.X = value; }
        }

        /// <summary>
        /// Turns the light on or off.
        /// </summary>
        public bool Enabled;

        /// <summary>
        /// Packed range, fallof, theta and phi, this is used for spotlights only.
        /// </summary>
        public Vector4 SpotData;

    }

    /// <summary>
    /// Defines the types of lights.
    /// </summary>
    public enum LightType
    {
        /// <summary>
        /// Most common used light. Similar to sun light so all objects in the scene are lit by this light from the same direction as if the light source is in infinite distance.
        /// </summary>
        Directional,

        /// <summary>
        /// Light source which emits light in all directions, the Direction parameter has no meaning for it.
        /// </summary>
        Point,

        /// <summary>
        /// Light source similar to a light bulb.
        /// </summary>
        Spot,

    }


}
